package com.teamone.etl.datasource.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.PageInfo;
import com.teamone.etl.datasource.dao.DataSourceAddDao;
import com.teamone.etl.datasource.entity.DataSource;
import com.teamone.etl.datasource.entity.TypeEnum;
import com.teamone.etl.datasource.pool.JdbcConnector;
import com.teamone.etl.datasource.pool.RedisConnector;
import com.teamone.etl.datasource.requset.DataSourceAddReq;
import com.teamone.etl.datasource.requset.RedisSourceAddReq;
import com.teamone.etl.datasource.service.DataSourceService;
import com.teamone.etl.exception.CommonCode;
import com.teamone.etl.exception.CustomException;
import com.teamone.etl.util.DesUtil;
import io.lettuce.core.dynamic.annotation.Param;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import static com.teamone.etl.constant.EtlConstant.TypeConstant.MYSQL;
import static com.teamone.etl.constant.EtlConstant.TypeConstant.REDIS;

/**
 * (DataSource)表控制层
 *
 * @author makejava
 * @since 2021-01-06 14:22:51
 */
@RestController
@RequestMapping("dataSource")
public class DataSourceController extends ApiController {
    /**
     * 服务对象
     */
    @Resource
    private DataSourceService dataSourceService;

    @Resource
    private DataSourceAddDao dataSourceAddDao;

    /**
     * @Description 初始化连接池
     * @Author WangZhuoRan
     * @Date 2021-01-07 10:2
     */
    @PostConstruct
    public void connectionPoolInit(){
        List<DataSource> idList = dataSourceService.getAllNotDisabled();
        JdbcConnector.initJdbcPoopMap(idList);
        RedisConnector.initRedisPoolMap(idList);
    }

    /**
     * 分页查询所有数据
     *
     * @param page       分页对象
     * @param dataSource 查询实体
     * @return 所有数据
     */
    @GetMapping
    public R<IPage<DataSource>> selectAll(Page<DataSource> page, DataSource dataSource) {
        return success(this.dataSourceService.page(page, new QueryWrapper<>(dataSource)));
    }

    /**
     *  模糊分类查询
     *
     * @param typeId 分类Id
     * @param name   连接数据库名称
     * @param page   每页数据
     * @param size   当前页数
     * @param flag   是否加密
     * @return  部分数据
     */
    @GetMapping("/search")
    public R<Object> search(@Param("typeId") Integer typeId,
                    @Param("name") String name,
                    @RequestParam(value = "page",defaultValue = "1") Integer page,
                    @RequestParam(value = "size",defaultValue = "10") Integer size,
                    @RequestParam(value = "flag",defaultValue = "0") Integer flag) {
        PageInfo<DataSource> search = dataSourceService.search(typeId, name, page, size);
        //DES加密
        if(flag != null && flag == 1){
            DesUtil desUtil = new DesUtil(DesUtil.KEY_ARR[0]);
            String s = JSONArray.toJSONString(search);
            System.out.println("加密前的数据"+s);
            String encryptStr = desUtil.encryptStr(s);
            return success(encryptStr);
        }
        return success(search);
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("{id}")
    public R<DataSource> selectOne(@PathVariable Serializable id) {
        return success(this.dataSourceService.getById(id));
    }


    /**
     * 获取数据源信息
     *
     * @param id 通过id获取数据源
     * @return 数据源信息
     */
    @GetMapping("/getDataSourceById")
    public R<Object> getById(@RequestParam("id") Integer id, @RequestParam("flag") Integer flag) {
        DataSource dataSourceById = dataSourceService.getDataSourceById(id);
        //flag控制是否 加密
        if(flag!=null && flag == 1) {
            //加密方式
            DesUtil desUtil = new DesUtil(DesUtil.KEY_ARR[1]);
            //将对象转为json字符串
            String jsonDataSource = JSON.toJSONString(dataSourceById);
            //转为map
            Map<String,String> maps = JSON.parseObject(jsonDataSource, new TypeReference<HashMap<String,String>>(){});
            //遍历 key value
            maps.forEach((key,value)-> maps.put(key, desUtil.encryptStr(value)));
            //将map转回json返回
            return success(JSON.toJSON(maps));
        }
         return success(dataSourceById);
    }

    /**
     * 新增数据
     *
     * @param dataSource 实体对象
     * @return 新增结果
     */
    @PostMapping
    public R<Boolean> insert(@RequestBody DataSource dataSource) {
        return success(this.dataSourceService.save(dataSource));
    }

    /**
     * 修改数据源
     *
     * @param dataSource 实体对象
     * @return 修改结果
     */
    @PutMapping("/updateDataSource")
    public R<Object> updateSource(@RequestBody DataSource dataSource) {

        Integer typeId = dataSource.getTypeId();
        if(typeId .equals(TypeEnum.TYPE_JDBC_ONE.getTypeid())){
            //刷新到jdbc数据源
            JdbcConnector.put(dataSource);
            //获取到当前数据源 查询是否在使用
            Boolean notWorked = JdbcConnector.isNotWorked(JdbcConnector.JDBC_POOL_MAP.get(dataSource.getId()));
            if(!notWorked){
                //返回正在使用
                return success("正在使用");
            }
            try {
                dataSourceService.updateSource(dataSource);
                return success(true);
            }catch (Exception e){
                return success(false);
            }
        }

        boolean connected = RedisConnector.isConnected(dataSource);
        if(connected) {
            dataSourceService.updateSource(dataSource);
            return success(true);
        }
        return success(false);

    }

    /**
     * 删除数据源
     *
     * @param idList 主键结合
     * @return 删除结果
     */
    @DeleteMapping
    public R<Object> delete(@RequestParam("idList") List<Integer> idList) throws CustomException {
        if(! CollectionUtils.isEmpty(idList)){
            return success(this.dataSourceService.removeByIdsAndCheckIsConnect(idList));
        }
        return failed("请选中至少一个数据源");
    }


    /**测试连接
     *
     * @param dataSource 数据源
     * @return 连接成功/失败
     */
    @PostMapping("/testConnect")
    public R<Boolean> testConnect(@RequestBody DataSource dataSource) throws CustomException {
        boolean flag;
        try {
            if(dataSource.getTypeId()==MYSQL){
                flag = dataSourceService.testMysqlConnect(dataSource);
            }else if(REDIS.equals(dataSource.getTypeId())){
                flag = dataSourceService.testRedisConnect(dataSource);
            }else{
                flag = false;
            }
        }catch (Exception e){
            throw new CustomException(CommonCode.CONNECTION_FAIL);
        }
        return success(flag);
    }


    /**添加mysql数据源
     *
     * @param dataSourceAddReq 添加信息
     */
    @PostMapping("/addMySqlSource")
    public R<Object> addMySqlSource(@RequestBody DataSourceAddReq dataSourceAddReq) throws CustomException {
        if(!StringUtils.isEmpty(dataSourceAddReq.getUsername())
        &&!StringUtils.isEmpty(dataSourceAddReq.getTypeId())
                &&!StringUtils.isEmpty(dataSourceAddReq.getRemarks())
                &&!StringUtils.isEmpty(dataSourceAddReq.getIsDisable())
                &&!StringUtils.isEmpty(dataSourceAddReq.getDbName())
                &&!StringUtils.isEmpty(dataSourceAddReq.getDatasourceUrl())
                &&!StringUtils.isEmpty(dataSourceAddReq.getDatasourcePort())
                &&!StringUtils.isEmpty(dataSourceAddReq.getDatasourceName())){
            dataSourceAddDao.insert(dataSourceAddReq);
            return success(true);
        }else {
            throw new CustomException(CommonCode.INVALID_PARAM);
        }
    }

    /**
     * 添加redis数据源
     * @param redisSourceAddReq 添加信息
     */
    @PostMapping("/addRedisSource")
    public R<Object> addRedisSource(@RequestBody RedisSourceAddReq redisSourceAddReq) throws CustomException {
        if(!StringUtils.isEmpty(redisSourceAddReq.getDatasourceUrl())
        &&!StringUtils.isEmpty(redisSourceAddReq.getDatasourcePort())
        &&!StringUtils.isEmpty(redisSourceAddReq.getDatasourceName())
                &&!StringUtils.isEmpty(redisSourceAddReq.getTypeId())
                &&!StringUtils.isEmpty(redisSourceAddReq.getIsDisable())){
            DataSourceAddReq dataSourceAddReq = new DataSourceAddReq();
            BeanUtils.copyProperties(redisSourceAddReq, dataSourceAddReq);
            dataSourceAddDao.insert(dataSourceAddReq);
            return success(true);
        }else {
            throw new CustomException(CommonCode.INVALID_PARAM);
        }
    }

    /**
     BI数据分析-执行SQL语句
     @param dataSourceId 数据源id
     @param dataBaseName 数据库名称
     @param tableName 表名
     @param sql SQL语句
     @return List<Map<String, String>> 字段相关信息,查询到的数据
     */
    @GetMapping("/dataAnalysis/{dataSourceId}")
    public R<Map<String,Object>> dataAnalysis(@PathVariable("dataSourceId") Integer dataSourceId,
                                @RequestParam("dataBaseName") String dataBaseName,
                                @RequestParam("tableName") String tableName,
                                @RequestParam("sql") String sql,
                                @RequestParam(value = "shouldExecuteRuleEngine",required = false,
                                        defaultValue = "false") boolean shouldExecuteRuleEngine) throws CustomException {
        Map<String,Object> results = dataSourceService.dataAnalysis(dataSourceId,
                dataBaseName,
                tableName,
                sql,
                shouldExecuteRuleEngine);
        return results==null?failed(CommonCode.CONNECTION_FAIL.msg()):success(results);
    }

    @GetMapping("/getAllDataSourceByDescription")
    public R<List<DataSource>> getAllDataSourceByDescription (@RequestParam(value = "description",required = false,defaultValue = "") String description){
        return success(dataSourceService.getAllNotDisabledByDescriptionAndClearSensitiveInformation(description));
    }

}